/*
The MIT License
Copyright (c) 2019 Lehrstuhl Informatik 11 - RWTH Aachen University
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE

This file is part of embeddedRTPS.

Author: i11 - Embedded Software, RWTH Aachen University
*/

#ifndef RTPS_MESSAGES_H
#define RTPS_MESSAGES_H

#include "rtps/common/types.h"
#include "rtps/storages/PBufWrapper.h"
// TODO endianess
typedef uint16_t ParameterId;
#define  PID_PAD 0x0000
#define  PID_SENTINEL  0x0001
#define  PID_USER_DATA  0x002c
#define  PID_TOPIC_NAME  0x0005
#define  PID_TYPE_NAME  0x0007
#define  PID_GROUP_DATA  0x002d
#define  PID_TOPIC_DATA  0x002e
#define  PID_DURABILITY  0x001d
#define  PID_DURABILITY_SERVICE  0x001e
#define  PID_DEADLINE  0x0023
#define  PID_LATENCY_BUDGET  0x0027
#define  PID_LIVELINESS  0x001b
#define  PID_RELIABILITY  0x001a
#define  PID_LIFESPAN  0x002b
#define  PID_DESTINATION_ORDER  0x0025
#define  PID_HISTORY  0x0040
#define  PID_RESOURCE_LIMITS  0x0041
#define  PID_OWNERSHIP  0x001f
#define  PID_OWNERSHIP_STRENGTH  0x0006
#define  PID_PRESENTATION  0x0021
#define  PID_PARTITION  0x0029
#define  PID_TIME_BASED_FILTER  0x0004
#define  PID_TRANSPORT_PRIORITY  0x0049
#define  PID_PROTOCOL_VERSION  0x0015
#define  PID_VENDORID  0x0016
#define  PID_UNICAST_LOCATOR  0x002f
#define  PID_MULTICAST_LOCATOR  0x0030
#define  PID_MULTICAST_IPADDRESS  0x0011
#define  PID_DEFAULT_UNICAST_LOCATOR  0x0031
#define  PID_DEFAULT_MULTICAST_LOCATOR  0x0048
#define  PID_METATRAFFIC_UNICAST_LOCATOR  0x0032
#define  PID_METATRAFFIC_MULTICAST_LOCATOR  0x0033
#define  PID_DEFAULT_UNICAST_IPADDRESS  0x000c
#define  PID_DEFAULT_UNICAST_PORT  0x000e
#define  PID_METATRAFFIC_UNICAST_IPADDRESS  0x0045
#define  PID_METATRAFFIC_UNICAST_PORT  0x000d
#define  PID_METATRAFFIC_MULTICAST_IPADDRESS  0x000b
#define  PID_METATRAFFIC_MULTICAST_PORT  0x0046
#define  PID_EXPECTS_INLINE_QOS  0x0043
#define  PID_PARTICIPANT_MANUAL_LIVELINESS_COUNT  0x0034
#define  PID_PARTICIPANT_BUILTIN_ENDPOINTS  0x0044
#define  PID_PARTICIPANT_LEASE_DURATION  0x0002
#define  PID_CONTENT_FILTER_PROPERTY  0x0035
#define  PID_PARTICIPANT_GUID  0x0050
#define  PID_PARTICIPANT_ENTITYID  0x0051
#define  PID_GROUP_GUID  0x0052
#define  PID_GROUP_ENTITYID  0x0053
#define  PID_BUILTIN_ENDPOINT_SET  0x0058
#define  PID_PROPERTY_LIST  0x0059
#define  PID_ENDPOINT_GUID  0x005a
#define  PID_TYPE_MAX_SIZE_SERIALIZED  0x0060
#define  PID_ENTITY_NAME  0x0062
#define  PID_KEY_HASH  0x0070
#define  PID_STATUS_INFO  0x0071


typedef enum BuildInEndpointSet
{
  DISC_BIE_PARTICIPANT_ANNOUNCER = 1 << 0,
  DISC_BIE_PARTICIPANT_DETECTOR = 1 << 1,
  DISC_BIE_PUBLICATION_ANNOUNCER = 1 << 2,
  DISC_BIE_PUBLICATION_DETECTOR = 1 << 3,
  DISC_BIE_SUBSCRIPTION_ANNOUNCER = 1 << 4,
  DISC_BIE_SUBSCRIPTION_DETECTOR = 1 << 5,

  DISC_BIE_PARTICIPANT_PROXY_ANNOUNCER = 1 << 6,
  DISC_BIE_PARTICIPANT_PROXY_DETECTOR = 1 << 7,
  DISC_BIE_PARTICIPANT_STATE_ANNOUNCER = 1 << 8,
  DISC_BIE_PARTICIPANT_STATE_DETECTOR = 1 << 9,

  BIE_PARTICIPANT_MESSAGE_DATA_WRITER = 1 << 10,
  BIE_PARTICIPANT_MESSAGE_DATA_READER = 1 << 11,
}BuildInEndpointSet;

// TODO endianess

extern const unsigned char SCHEME_CDR_LE[2];
extern const unsigned char SCHEME_PL_CDR_LE[2];

typedef struct ParameterList_t {
  ParameterId pid;
  uint16_t length;
  // Values follow
}ParameterList_t;
//} __attribute__((packed));

typedef uint8_t SubmessageKind;
#define  PAD  0x01            /* Pad */
#define  ACKNACK  0x06        /* AckNack */
#define  HEARTBEAT  0x07      /* Heartbeat */
#define  GAP  0x08            /* Gap */
#define  INFO_TS  0x09        /* InfoTimestamp */
#define  INFO_SRC  0x0c       /* InfoSource */
#define  INFO_REPLY_IP4  0x0d /* InfoReplyIp4 */
#define  INFO_DST  0x0e       /* InfoDestination */
#define  INFO_REPLY  0x0f     /* InfoReply */
#define  NACK_FRAG  0x12      /* NackFrag */
#define  HEARTBEAT_FRAG  0x13 /* HeartbeatFrag */
#define  DATA  0x15           /* Data */
#define  DATA_FRAG  0x16      /* DataFrag */


typedef uint8_t SubMessageFlag;
#define  FLAG_ENDIANESS  (1 << 0)
#define  FLAG_BIG_ENDIAN  (0 << 0)
#define  FLAG_LITTLE_ENDIAN  (1 << 0)
#define  FLAG_INVALIDATE  (1 << 1)
#define  FLAG_INLINE_QOS  (1 << 1)
#define  FLAG_NO_PAYLOAD  (0 << 3 | 0 << 2)
#define  FLAG_DATA_PAYLOAD  (0 << 3 | 1 << 2)
#define  FLAG_FINAL  (1 << 1)
#define  FLAG_HB_LIVELINESS  (1 << 2)

extern const unsigned char RTPS_PROTOCOL_NAME[4];

typedef struct Header {
  unsigned char protocolName[4];
  struct ProtocolVersion_t protocolVersion;
  struct VendorId_t vendorId;
  struct GuidPrefix_t guidPrefix;
}Header;

typedef struct SubmessageHeader {
  SubmessageKind submessageId;
  uint8_t flags;
  uint16_t octetsToNextHeader;
}SubmessageHeader;

typedef struct SubmessageData {
  struct SubmessageHeader header;
  uint16_t extraFlags;
  uint16_t octetsToInlineQos;
  struct EntityId_t readerId;
  struct EntityId_t writerId;
  struct SequenceNumber_t writerSN;
}SubmessageData;

typedef struct SubmessageHeartbeat {
  struct SubmessageHeader header;
  struct EntityId_t readerId;
  struct EntityId_t writerId;
  struct SequenceNumber_t firstSN;
  struct SequenceNumber_t lastSN;
  struct Count_t count;
}SubmessageHeartbeat;

typedef struct SubmessageInfoDST {
  struct SubmessageHeader header;
  struct GuidPrefix_t guidPrefix;
}SubmessageInfoDST;

typedef struct SubmessageAckNack {
  SubmessageHeader header;
  struct EntityId_t readerId;
  struct EntityId_t writerId;
  struct SequenceNumberSet readerSNState;
  struct Count_t count;
}SubmessageAckNack;

typedef struct MessageProcessingInfo {
  uint8_t *data;
  DataSize_t size;

  //! Offset to the next unprocessed byte
  DataSize_t nextPos;
}MessageProcessingInfo;

inline uint8_t *getPointerToCurrentPos(struct MessageProcessingInfo *Info)
{
  return Info->data+Info->nextPos;
}
//! Returns the size of data which isn't processed yet
inline DataSize_t getRemainingSize(struct MessageProcessingInfo *Info)  
{ 
  return Info->size - Info->nextPos; 
}

uint16_t HeaderGetRawSize(void);
uint16_t SubmessageHeaderGetRawSize(void);
uint16_t SubmessageDataGetRawSize(void);
uint16_t SubmessageHeartbeatGetRawSize(void);
//static const uint16_t SubmessageInfoDSTGetRawSize();
uint16_t getRawSizeWithoutSNSet();
uint16_t SubmessageAckNackGetRawSize(const SequenceNumberSet set);

bool deserializeMessageHeader(struct MessageProcessingInfo *info, Header *header);
bool deserializeMessageSubmessageHeader(struct MessageProcessingInfo *info, struct SubmessageHeader *header);
bool deserializeMessageSubmessageData(struct MessageProcessingInfo *info, struct SubmessageData *msg);
bool deserializeMessageSubmessageHeartbeat(struct MessageProcessingInfo *info, struct SubmessageHeartbeat *msg);
bool deserializeMessageSubmessageAckNack(struct MessageProcessingInfo *info, struct SubmessageAckNack *msg);
bool serializeMessageHeader(struct rtps_PBufWrapper *buffer, struct Header *header);
bool serializeMessageSubmessageHeader(struct rtps_PBufWrapper *buffer, struct SubmessageHeader header);
//bool serializeMessageSubmessageInfoDST(Buffer *buffer, struct SubmessageInfoDST *msg);
bool serializeMessageSubmessageData(struct rtps_PBufWrapper *buffer, struct SubmessageData *msg);
bool serializeMessageSubmessageHeartbeat(struct rtps_PBufWrapper *buffer, struct SubmessageHeartbeat *msg);
bool serializeMessageSubmessageAckNack(struct rtps_PBufWrapper *buffer, struct SubmessageAckNack msg);


#endif // RTPS_MESSAGES_H
